#include"stdafx.h"
#include <map>
WLLineBatch* g_pLineBatch = new WLLineBatch();
WLArchive& operator << (WLArchive& Ar, WLPrimFace &Face )
{
	for ( int i = 0; i<3; i++ )
	{
		Ar<<Face.VertIndex[i];	
	}
	return Ar;
}
WLArchive& operator << (WLArchive& Ar, WLMaterial &Mat )
{
	Ar<<Mat.m_TexDiffuse;	
	return Ar;
}

void WLMesh::Serialize(WLArchive& Ar)
{
	Ar<<m_Verts;
	Ar<<m_Faces;
	Ar<<m_UVWs;
	Ar<<m_TexFaces;
	Ar<<m_FaceMatIndex;
	Ar<<m_SmoothGroup;
	Ar<<m_Materials;
}

#include<algorithm>
class SMeshVertIndex
{
public:
	int VertIndex;
	int TVertIndex;
	int SmoothGroup;
	friend bool operator== ( const SMeshVertIndex& lh, const SMeshVertIndex& rh)
	{
		return (lh.VertIndex == rh.VertIndex
			&&lh.TVertIndex == rh.TVertIndex
			&&lh.SmoothGroup == rh.SmoothGroup
			);
	}
	SMeshVertIndex()
	{}
	SMeshVertIndex(const SMeshVertIndex& SM)
	{
		VertIndex = SM.VertIndex;
		TVertIndex = SM.TVertIndex;
	}
};
int findMeshVertIndex(std::vector<SMeshVertIndex>& MeshVertIndex, SMeshVertIndex & inIndex )
{
	for ( unsigned int i = 0; i<MeshVertIndex.size(); i++ )
	{
		if ( MeshVertIndex[i] == inIndex )
			return i;
	
	}
	return -1;

}

void VNormal::AddNormal(WLVector3 &n,DWORD s) 
{ 
	if (!(s&smooth) && init) 
	{ 
		if (next) 
			next->AddNormal(n,s); 
		else 
		{ 
			next = new VNormal(n,s); 
		}
	}
	else 
	{ 
		norm += n; 
		smooth |= s; 
		init = TRUE; 
	}
}


// Retrieves a normal if the smoothing groups overlap or there is 

// only one in the list 

WLVector3 &VNormal::GetNormal(DWORD s) 
{
   if (smooth&s || !next)
	   return norm; 
   else 
	   return next->GetNormal(s);
}

 

// Normalize each normal in the list 

void VNormal::Normalize() 
{ 
	VNormal *ptr = next, *prev = this; 
	while (ptr) 
	{ 
		if (ptr->smooth&smooth) 
		{ 
			norm += ptr->norm; 
			prev->next = ptr->next; 
			delete ptr; 
			ptr = prev->next; 
		} 
		else 
		{ 
			prev = ptr; 
			ptr = ptr->next; 
		} 
	}
	norm = norm.Normalize(); 
	if (next)
		next->Normalize();
}

void WLPrimData::ComputeVertexNormals(std::vector<VNormal>& vnorms)
{
	WLVector3 v0, v1, v2;
	WLVector3 fnorm;
	VNormal tmpNormal;
	vnorms.insert(vnorms.begin(),m_PositionData.size(),tmpNormal);

	for (unsigned int i = 0; i < m_Faces.size(); i++)
	{
		// Calculate the surface normal
		v0 = m_PositionData[m_Faces[i].VertIndex[0]];
		v1 = m_PositionData[m_Faces[i].VertIndex[1]];
		v2 = m_PositionData[m_Faces[i].VertIndex[2]];
		fnorm = WLVec3Cross((v1-v0),(v2-v1));
		for (unsigned int j=0; j<3; j++)
		{
			vnorms[m_Faces[i].VertIndex[j]].AddNormal(fnorm,DWORD(this->m_SmoothGroupArray[i]));
		}
		//fnorms[i] = fnorms[i].Normalize();
	}
	for (unsigned int i=0; i < m_PositionData.size(); i++)
	{
		vnorms[i].Normalize();
	}
}

int WLPrimData::BuildIndexPrimitive(std::vector<int>& FaceIDs, int Index, std::vector<int>& FaceSMs)
{
	std::vector<SMeshVertIndex> MeshVertIndex;
	std::vector<VNormal> VNorms;
	SMeshVertIndex tmpMeshVertIndex;
	WLPrimFace tmpFace;
	m_Faces.insert(m_Faces.begin(),FaceIDs.size(),tmpFace);
	m_SmoothGroupArray.insert(m_SmoothGroupArray.begin(),FaceIDs.size(),0);
	for ( unsigned int i = 0; i<FaceIDs.size(); i++ )
	{
		WLPrimFace& Face = *(m_pOwner->GetFace(FaceIDs[i]));
		WLPrimFace& TFace = *(m_pOwner->GetTFace(FaceIDs[i]));
		tmpMeshVertIndex.SmoothGroup = *(m_pOwner->GetFaceSmoothGroup(FaceIDs[i]));
		for ( unsigned int j = 0; j<3; j++ )
		{
			tmpMeshVertIndex.VertIndex = Face.VertIndex[j]-1;
			tmpMeshVertIndex.TVertIndex = TFace.VertIndex[j]-1;
			int FindIndex = findMeshVertIndex(MeshVertIndex,tmpMeshVertIndex );
			if ( FindIndex<0 )
			{
				m_Faces[i].VertIndex[j] = MeshVertIndex.size();
				MeshVertIndex.push_back(tmpMeshVertIndex);
			}
			else
			{
				m_Faces[i].VertIndex[j] = FindIndex;
			}
		}
		m_SmoothGroupArray[i] = *(m_pOwner->GetFaceSmoothGroup(FaceIDs[i]));
	}

	for ( unsigned int i = 0; i<MeshVertIndex.size(); i++ )
	{
		WLVector3 Pos = *(m_pOwner->GetVert(MeshVertIndex[i].VertIndex));
		WLVector3 UVW = *(m_pOwner->GetTVert(MeshVertIndex[i].TVertIndex));
		m_PositionData.push_back(Pos);
		m_UVWData.push_back(UVW);
	}
	ComputeVertexNormals(VNorms);
	for ( unsigned int i = 0; i<MeshVertIndex.size(); i++ )
	{
		m_NormalData.push_back(VNorms[i].norm);
	}
	m_pMaterial = new WLMaterial();
	m_pMaterial->m_TexDiffuse = m_pOwner->GetMaterial(Index).m_TexDiffuse;
	m_PrimitiveCount = m_Faces.size();
	return 1;
}
int WLMesh::Build()
{
	WLPrimitive::Build();
	std::map<int,std::vector<int>> FaceMatMap;
	for ( unsigned int i = 0; i<m_FaceMatIndex.size(); i++ )
	{
		FaceMatMap[m_FaceMatIndex[i]].push_back(i);
	}
	std::map<int,std::vector<int>>::iterator It;
	int i = 0;
	for(It = FaceMatMap.begin(); It != FaceMatMap.end(); It++)
	{
		m_DataArray.push_back(this);
		m_DataArray[i++].BuildIndexPrimitive(FaceMatMap[i],i-1,m_SmoothGroup);
	}	
	return 1;
}
WLArchive& operator << (WLArchive& Ar, WLRawBoneData &Bone )
{
	Ar<<Bone.Parent;
	Ar<<Bone.BoneName;
	Ar<<Bone.Position;
	return Ar;
}
WLArchive& operator << (WLArchive& Ar, WLSkinData &Skin )
{
	Ar<<Skin.BoneIndex;
	Ar<<Skin.Weight;
	return Ar;
}

WLArchive& operator << (WLArchive& Ar, WLVertexSkin &Skin )
{
	Ar<<Skin.DataArray;
	return Ar;
}

int WLBoneMesh::Build()
{
	int Result = WLMesh::Build();
	if ( Result == 0 )
		return 0;
	//for ( unsigned int i = 0; i<m_BoneArray.size(); i++ )
	//{
	//	if ( m_BoneArray[i].Parent )
	//	{
	//		int Parent = m_BoneArray[i].Parent - 1;
	//		g_pLineBatch->AddLine(m_BoneArray[i].Position,m_BoneArray[Parent].Position,0xffff0000);
	//	}
	//}
	return 1;
}
void WLBoneMesh::Serialize(class WLArchive& Ar)
{
	WLMesh::Serialize(Ar);
	Ar<<m_BoneArray;
	Ar<<m_SkinBoneArray;
	Ar<<m_SkinDataArray;
}
int WLLineBatch::AddLine( WLVector3 Start, WLVector3 End, DWORD Color )
{
	if ( m_DataArray.size() == 0 )
	{
		Build();
	}
	Reversion++;
	WLPrimData& Data = m_DataArray[0];
	Data.m_PositionData.push_back(Start);
	Data.m_PositionData.push_back(End);
	Data.m_ColorData.push_back(Color);
	Data.m_ColorData.push_back(Color);
	Data.SetPrimitiveCount(Data.m_PositionData.size()/2);
	return 1;
}
int WLLineBatch::Build()
{
	WLPrimData Data;
	Data.m_pOwner = this;
	Data.m_PTType = GetPrimitiveType();
	
	Data.SetPrimitiveCount(0);
	m_DataArray.push_back(Data);
	return 1;
}
int WLGrid::Build()
{
	WLPrimitive::Build();
	
	WLPrimData Data;
	Data.m_pOwner = this;
	Data.m_PTType = GetPrimitiveType();
	float Length = (float(m_HalfSegCount))*m_EdgeLength;
	//x axis
	for ( int i = 0; i<m_HalfSegCount; i++ )
	{
		WLVector3 V1,V2,V3,V4,V5,V6;
		V1.x = -Length;
		V1.y = 0.f;
		V1.z = (m_HalfSegCount-i - 1.f) * m_EdgeLength;
		Data.m_PositionData.push_back(V1);
		V2.x = Length;
		V2.y = 0.f;
		V2.z = (m_HalfSegCount-i - 1.f) * m_EdgeLength;
		Data.m_PositionData.push_back(V2);

		V1.x = -Length;
		V1.y = 0.f;
		V1.z = -(m_HalfSegCount-i - 1.f) * m_EdgeLength;
		Data.m_PositionData.push_back(V1);
		V2.x = Length;
		V2.y = 0.f;
		V2.z = -(m_HalfSegCount-i - 1.f) * m_EdgeLength;
		Data.m_PositionData.push_back(V2);
	}
	//z axis
	for ( int i = 0; i<m_HalfSegCount; i++ )
	{
		WLVector3 V1,V2,V3,V4,V5,V6;
		V1.x = (m_HalfSegCount-i - 1.f) * m_EdgeLength;
		V1.y = 0.f;
		V1.z = -Length;
		Data.m_PositionData.push_back(V1);
		V2.x = (m_HalfSegCount-i - 1.f) * m_EdgeLength;
		V2.y = 0.f;
		V2.z = Length;
		Data.m_PositionData.push_back(V2);

		V1.x = -(m_HalfSegCount-i - 1.f) * m_EdgeLength;
		V1.y = 0.f;
		V1.z = -Length;
		Data.m_PositionData.push_back(V1);
		V2.x = -(m_HalfSegCount-i - 1.f) * m_EdgeLength;
		V2.y = 0.f;
		V2.z = Length;
		Data.m_PositionData.push_back(V2);
	}
	Data.m_ColorData.insert(Data.m_ColorData.begin(),Data.m_PositionData.size(),0xffffffff);
	m_Location = WLVector3(0.f,0.f,0.f);
	m_Rotation = WLQuaternion(0,0,0,0);
	Data.m_ColorData[m_HalfSegCount*4-4] = 0xff000000;
	Data.m_ColorData[m_HalfSegCount*4-3] = 0xff000000;
	Data.m_ColorData[m_HalfSegCount*4-2] = 0xff000000;
	Data.m_ColorData[m_HalfSegCount*4-1] = 0xff000000;

	Data.m_ColorData[m_HalfSegCount*8-4] = 0xff000000;
	Data.m_ColorData[m_HalfSegCount*8-3] = 0xff000000;
	Data.m_ColorData[m_HalfSegCount*8-2] = 0xff000000;
	Data.m_ColorData[m_HalfSegCount*8-1] = 0xff000000;
	Data.SetPrimitiveCount(Data.m_PositionData.size()/2);
	m_DataArray.push_back(Data);
	return 1;
}